/*
 * ShoppingCartManager.java
 * business
 *
 * Created by ChenTao on 2016/9/9.
 *
 * Copyright (c) 2016年 yidiandao. All rights reserved.
 */

package com.yidiandao.business.manager;

import android.support.v4.util.ArrayMap;

import com.google.gson.Gson;
import com.yidiandao.business.data.bean.CartBean;
import com.yidiandao.business.data.bean.Discount;
import com.yidiandao.business.data.bean.FavourableInfo;
import com.yidiandao.business.data.bean.Goods;
import com.yidiandao.business.data.bean.Shop;
import com.yidiandao.business.utils.GsonProvider;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 购物车Manager
 */
public class ShoppingCartManager {

    /**
     * 购物车：店铺与店铺所有商品的映射
     */
    private Map<Shop, List<Goods>> mShoppingCartMap = new ArrayMap<>();

    /**
     * 购物车：已选中商品的集合
     */
    private List<Goods> mSelectedGoodsList = new ArrayList<>();

    /**
     * 购物车失效商品列表.<b>服务器没有库存的商品</b>
     */
    private List<Goods> mInvalidGoodsList = new ArrayList<>();

    private List<OnShoppingCartStatisticsListener> mStatisticsListeners = new ArrayList<>();

    private List<OnShoppingCartGoodsItemNumberChangeListener> mGoodsNumberChangeListeners =
            new ArrayList<>();

    private ShoppingCartManager() {
    }

    public static ShoppingCartManager getInstance() {
        // 避免出现DCL失效问题
        return Singleton.instance;
    }

    /**
     * 判断购物车是否有选中的商品
     */
    public boolean isShoppingCartHasSelectedGoods() {
        return mSelectedGoodsList.size() != 0;
    }

    /**
     * 同步服务器购物车. <p> <p>购物车刷新时调用
     */
    public void initServerCartBeans(List<CartBean> serverCarts) {
        // 每次从服务器获取购物车列表数据，先重置购物车
        // 清空购物车列表
        mShoppingCartMap.clear();
        // 清空购物车中已选中的商品列表
        mSelectedGoodsList.clear();

        for (CartBean cart : serverCarts) {
            mShoppingCartMap.put(cart.getSupplier(), cart.getGoodsList());
        }
    }

    /**
     * 更新单个订单信息
     */
    public void updateCartInfo(CartBean cartBean) {
        Shop shop = cartBean.getSupplier();
        List<Goods> goodsList = cartBean.getGoodsList();
        // 先移除
        mShoppingCartMap.remove(shop);
        // 再添加，避免key不变出现bug
        mShoppingCartMap.put(shop, goodsList);
    }

    /**
     * 购物车总的价格计算均在这个方法中完成
     */
    private void notifyPriceAndSelectedCountChanged(float totalPrice, int totalSelectedCount) {

        // 刷新满减活动的统计
        refreshReduceState();

        // 总的运费
        float totalCarriageOfShoppingCart = getTotalCarriageOfShoppingCart();

        // 总的减免金额
        float totalReducePrice = ReduceManager.getInstance().getAllSelectedReduceInfoPrice();
        // 所有赠品的价格
        float allSelectedGiftPrice = GiftManager.getInstance().getAllSelectedGiftsPrice();

        // 所有赠品的数量
        int allSelectedGiftCount = GiftManager.getInstance().getAllSelectedGiftCount();

        // 减免前的价格：包括赠品的价格和商品的价格、运费
        float totalPriceBeforeReduce =
                totalPrice + allSelectedGiftPrice + totalCarriageOfShoppingCart;
        // 减免后的价格，包括赠品的价格和商品的价格，包含运费、去除减免的价格
        float totalPriceAfterReduce = totalPriceBeforeReduce - totalReducePrice;
        // 所有商品与赠品的数量
        int totalSelectedCountWithGift = totalSelectedCount + allSelectedGiftCount;

        for (OnShoppingCartStatisticsListener listener : mStatisticsListeners) {

            listener.onPriceAndSelectedCountChanged(totalPriceBeforeReduce, totalPriceAfterReduce,
                    totalReducePrice, totalSelectedCountWithGift);
        }
    }

    /**
     * 计算所有店铺的运费
     */
    private float getTotalCarriageOfShoppingCart() {

        float totalCarriage = 0;
        Set<Shop> shops = mShoppingCartMap.keySet();

        for (Shop shop : shops) {
            // 商品总价格为0时，直接设置运费为0
            calculateShopCarriage(shop);
            totalCarriage += shop.getTotalLogisticsMoney();
        }
        return totalCarriage;
    }

    /**
     * 当选择赠品发生该改变时，通知购物车底部统计也发生改变.   <p>供外部调用
     */
    public void notifyShoppingCartStatisticsChanged() {
        notifyPriceAndSelectedCountChanged(getTotalSelectedGoodsPrice(), getTotalSelectCount());
    }

    /**
     * 当定向刷新订单时，重新统计是否全选 <p> <p>供外部调用
     */
    public void notifyTotalSelectedStateChanged() {
        notifyAllGoodsCheckChanged(isAllShopSelected());
    }

    private void notifyAllGoodsCheckChanged(boolean isSelectedAllGoods) {
        for (OnShoppingCartStatisticsListener listener : mStatisticsListeners) {
            listener.onAllGoodsCheckChanged(isSelectedAllGoods);
        }
    }

    /**
     * 获取当前店铺选中的商品的总价
     */
    float getTotalPriceOfShopSelectedGoods(Shop shop) {
        float totalPrice = 0;
        List<Goods> goodsList = mShoppingCartMap.get(shop);

        if (goodsList == null) {
            return totalPrice;
        }

        for (Goods goods : goodsList) {
            if (goods.isSelected()) {
                totalPrice += goods.getGoodsPrice() * goods.getGoodsNumber();
            }
        }
        return totalPrice;
    }

    /**
     * 获取店铺当前店铺所有优惠之后的价格
     */
    private float getTotalPriceOfShopSelectedGoodsAfterAllFavourable(Shop shop) {
        float totalPrice = 0;
        List<Goods> goodsList = mShoppingCartMap.get(shop);

        if (null == goodsList || goodsList.size() == 0) {
            return totalPrice;
        }

        for (Goods goods : goodsList) {

            if (goods.isSelected()) {
                // 加上计算选中商品的价格
                totalPrice += goods.getGoodsPrice() * goods.getGoodsNumber();

                // 当前商品的活动信息
                FavourableInfo favourableInfo = goods.getFavourableInfo();
                if (favourableInfo != null) {
                    if (FavourableInfo.TYPE_GIFT.equals(favourableInfo.getType())) {
                        // 加上 单品满赠/加价购活动优惠
                        Goods chooseGift = favourableInfo.getChooseGift();
                        if (chooseGift != null) {
                            totalPrice += chooseGift.getGoodsPrice() + chooseGift.getGoodsNumber();
                        }
                    } else {
                        // 减去 单品满减活动优惠
                        totalPrice -= favourableInfo.getDiscountMoney();
                    }
                }
            }
        }

        // 减去 订单减免的价格
        FavourableInfo favourableInfo = shop.getFavourableInfo();
        if (favourableInfo != null) {
            // 直接获取满足条件的满减活动
            Discount bestDiscount = favourableInfo.getBestDiscount();
            if (bestDiscount != null) {
                totalPrice -= bestDiscount.getDiscount();
            }
        }

        // TODO 暂时没有订单满赠的活动

        return totalPrice;
    }

    /**
     * 计算当前店铺的运费
     */
    public void calculateShopCarriage(Shop shop) {

        if (isAllGoodsOfShopUnSelected(shop)) {
            // 当前店铺所有商品均未选中 运费为0
            shop.setTotalLogisticsMoney(0);
            return;
        }

        float totalPriceOfShopSelectedGoods = getTotalPriceOfShopSelectedGoodsAfterAllFavourable(
                shop);

        if (totalPriceOfShopSelectedGoods < shop.getLogisticsFreeMoney()) {
            // 不满足减免运费的条件
            shop.setTotalLogisticsMoney(shop.getLogisticsFee());
        } else {
            // 满足减免运费的条件
            shop.setTotalLogisticsMoney(0);
        }
    }

    /**
     * 初始化失效商品列表
     */
    public void initInvalidGoodsList(List<Goods> goodsList) {
        clearInvalidGoodsList();
        mInvalidGoodsList.addAll(goodsList);
    }

    /**
     * 清除失效的商品
     */
    public void clearInvalidGoodsList() {
        mInvalidGoodsList.clear();
    }

    /**
     * 获取失效商品的catIds
     */
    public String getInvalidGoodsRecIds() {

        StringBuilder sb = new StringBuilder();

        for (Goods goods : mInvalidGoodsList) {
            sb.append(goods.getRecId());
            sb.append(",");
        }

        if (mInvalidGoodsList.size() == 0) {
            sb.append(",");
        }

        // 获取最后一个 "," 的位置
        String recIds = sb.toString();
        int lastIndex = recIds.lastIndexOf(",");

        return recIds.substring(0, lastIndex);
    }

    /**
     * 修改购物车中商品的数量
     *
     * @param goods 商品
     */
    public void updateGoodsCount(Goods goods) {
        boolean selected = goods.isSelected();
        // 先移除
        mSelectedGoodsList.remove(goods);
        // 如果是选中，再更新
        if (selected) {
            mSelectedGoodsList.add(goods);
        }

        notifyPriceAndSelectedCountChanged(getTotalSelectedGoodsPrice(), getTotalSelectCount());
    }

    /**
     * 选择单个 商品
     */
    public void selectSingleGoods(Goods goods, boolean isSelected) {
        goods.setSelected(isSelected);

        // 当个商品  单选/ 反选时 修改统计价格与数量
        updateGoodsCount(goods);
    }

    /**
     * 单机选择 / 反选 所有商品
     *
     * @param isSelectedAllGoods 是否是选择所有商品
     */
    public void selectAllGoodsOfShoppingCart(boolean isSelectedAllGoods) {
        Set<Shop> shops = mShoppingCartMap.keySet();
        for (Shop shop : shops) {
            // 里面已经触发了 数量与价格的回掉
            selectAllGoodsOfShop(shop, isSelectedAllGoods);
        }

        // 触发所有商品选择/反选的回掉
        notifyAllGoodsCheckChanged(isSelectedAllGoods);
        // 重新统计价格信息
        notifyPriceAndSelectedCountChanged(getTotalSelectedGoodsPrice(), getTotalSelectCount());
    }

    /**
     * 选择/反选 单个酒商下的所有商品
     *
     * @param shop               商店
     * @param isSelectedAllGoods 是否选择当前酒商下的所有商品
     */
    public void selectAllGoodsOfShop(Shop shop, boolean isSelectedAllGoods) {
        shop.setSelected(isSelectedAllGoods);

        List<Goods> goodsList = mShoppingCartMap.get(shop);
        for (Goods goods : goodsList) {
            goods.setSelected(isSelectedAllGoods);

            // 酒商标题 单选/ 反选时 修改统计价格与数量
            updateGoodsCount(goods);
        }

        // 全选店铺/反选店铺商品时，重新计算店铺的运费 todo 暂时注释
        calculateShopCarriage(shop);
    }

    /**
     * 刷新订单减免、或商品减免的情况
     */
    private void refreshReduceState() {
        ReduceManager.getInstance().calculateBestOrderReduce();
    }

    /**
     * 单机一个组，底部编辑菜单实现全选/反选
     *
     * @param shop 当前组
     */
    public void clearOrSelectAllGoodsByShop(Shop shop) {

        boolean isShopSelected = shop.isSelected();

        if (!isShopSelected) {
            // 如果当前店铺未被选中，直接取消全选
            notifyAllGoodsCheckChanged(false);
            return;
        }

        // 当前商品被选中
        notifyAllGoodsCheckChanged(isAllShopSelected());
    }

    /**
     * 购物车中所有的组是否都已选中
     */
    public boolean isAllShopSelected() {
        Set<Shop> shops = mShoppingCartMap.keySet();

        for (Shop shop : shops) {
            if (!shop.isSelected()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 单机单个商品时，清除/选中当前的组;底部操作栏:全选/取消全选 <p> <p>如果当前组中有一个商品未选中，则取消选中当前的组； <p>
     * <p>如果当前的组中所有的商品都已经选中，则选中当前的组； <p> <p>如果购物车中的所有商品都被全部选中，则会选中操作栏的“全选”按钮； <p>
     * <p>如果购物车中的有商品未被选中，则会取消选中操作栏的“全选”按钮。
     *
     * @param goods 取消选择的商品
     */
    public void clearOrSelectShopByGoods(Goods goods) {

        Set<Shop> shops = mShoppingCartMap.keySet();

        // 当前商品是否属于组的标记
        boolean groupBingo = false;

        int allGroupSelectCount = 0;

        for (Shop shop : shops) {

            // 找到当前商品所属的组
            List<Goods> goodsList = mShoppingCartMap.get(shop);
            for (Goods innerGoods : goodsList) {
                if (innerGoods.equals(goods)) {
                    shop.setSelected(false);
                    // 当前商品属于该组
                    groupBingo = true;
                    break;
                }
            }

            // 判断当前组中的所有商品是否被选中
            if (!groupBingo) {
                // 当前商品不属于当前的组，如果不属于该组，则继续判断当前组中的商品全部被选中
                boolean allGoodsOfShopSelect = isAllGoodsOfShopSelected(shop);
                // 同时需要根据组内商品的选中状态更改的组的选中状态
                shop.setSelected(allGoodsOfShopSelect);

                if (allGoodsOfShopSelect) {
                    allGroupSelectCount++;
                }

                // 结束本次循环,不向下执行
                continue;
            }

            // 重置当前商品是否属于组的标记
            groupBingo = false;

            // 当前商品属于该组
            // 当前商品是否选中
            boolean selected = goods.isSelected();
            if (!selected) {
                // 如果商品未选中，则取消组的选择
                shop.setSelected(false);
            } else {
                // 如果当前商品已被选中，继续判断当前组的其他商品是否被选中
                boolean allGoodsOfShopSelect = isAllGoodsOfShopSelected(shop);
                shop.setSelected(allGoodsOfShopSelect);

                if (allGoodsOfShopSelect) {
                    // 如果当前组的商品全部选中，则统计有一个组已经全选选中
                    allGroupSelectCount++;
                }
            }

            // 计算店铺选中的商品的价格 todo 暂时注释
            //            calculateShopCarriage(shop);
        }

        // 回调：所有的商品是否全部选中
        notifyAllGoodsCheckChanged(allGroupSelectCount == shops.size());
    }

    /**
     * 当前店铺的所有商品均未选中
     */
    public boolean isAllGoodsOfShopUnSelected(Shop shop) {
        List<Goods> goodsList = mShoppingCartMap.get(shop);
        for (Goods goods : goodsList) {
            if (goods.isSelected()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 修改购物车的模式
     *
     * @param isEditMode 是否是编辑模式
     */
    public void changeShoppingCartMode(boolean isEditMode) {
        Set<Shop> shopList = mShoppingCartMap.keySet();
        for (Shop shop : shopList) {
            shop.setEditMode(isEditMode);
            List<Goods> goodsList = mShoppingCartMap.get(shop);
            for (Goods goods : goodsList) {
                goods.setEditMode(isEditMode);
            }
        }
    }

    /**
     * 获取指定商店中所有商品的价格
     *
     * @param shop 指定商店
     */
    public float getTotalPriceOfShop(Shop shop) {

        float totalPrice = 0f;

        // 店铺中的所有商品
        List<Goods> goodsListOfShop = mShoppingCartMap.get(shop);

        for (Goods goods : goodsListOfShop) {
            totalPrice += goods.getGoodsPrice() * goods.getGoodsNumber();
        }

        return totalPrice;
    }

    /**
     * 判断当前组中的商品是否已经全部选择
     */
    public boolean isAllGoodsOfShopSelected(Shop shop) {

        // 找出当前组中的所有商品
        List<Goods> goodsList = mShoppingCartMap.get(shop);

        for (Goods goods : goodsList) {
            if (!goods.isSelected()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 获取购物车所有选中商品的价格（已对数量进行计算）
     */
    private float getTotalSelectedGoodsPrice() {

        float totalPrice = 0;

        for (Goods goods : mSelectedGoodsList) {
            int count = goods.getGoodsNumber();
            float price = goods.getGoodsPrice() * count;
            totalPrice += price;
        }

        return totalPrice;
    }

    /**
     * 获取购物车所有选中商品的数量
     */
    private int getTotalSelectCount() {

        int totalCount = 0;

        for (Goods goods : mSelectedGoodsList) {
            int count = goods.getGoodsNumber();
            totalCount += count;
        }

        return totalCount;
    }

    /**
     * 生成已选中的商品rec_id与数量goods_number的json数据
     */
    public String getAllSelectedGoodsRecJson() {
        Gson gson = GsonProvider.getExposeGson();
        return gson.toJson(mSelectedGoodsList);
    }

    /**
     * 获取购物车所有商品的rec_json. [{rec_id,goods_number},{...}]
     */
    public String getAllGoodsRecJson() {

        List<Goods> allGoodsOfShoppingCart = new ArrayList<>();

        Set<Shop> shops = mShoppingCartMap.keySet();
        for (Shop shop : shops) {
            List<Goods> goodsList = mShoppingCartMap.get(shop);
            allGoodsOfShoppingCart.addAll(goodsList);
        }

        Gson gson = GsonProvider.getExposeGson();
        return gson.toJson(allGoodsOfShoppingCart);
    }

    /**
     * 获取购物车中所有已选中商品的goods_id
     */
    public String getAllSelectedGoodsGoodsIds() {
        StringBuilder sb = new StringBuilder();

        for (Goods goods : mSelectedGoodsList) {
            sb.append(goods.getGoodsId());
            sb.append(",");
        }

        if (mSelectedGoodsList.size() == 0) {
            sb.append(",");
        }

        // 获取最后一个 "," 的位置
        String recIds = sb.toString();
        int lastIndex = recIds.lastIndexOf(",");

        return recIds.substring(0, lastIndex);
    }

    /**
     * 获取购物车中所有已选中商品的rec_id
     */
    public String getAllSelectedGoodsRecIds() {

        StringBuilder sb = new StringBuilder();

        for (Goods goods : mSelectedGoodsList) {
            sb.append(goods.getRecId());
            sb.append(",");
        }

        if (mSelectedGoodsList.size() == 0) {
            sb.append(",");
        }

        // 获取最后一个 "," 的位置
        String recIds = sb.toString();
        int lastIndex = recIds.lastIndexOf(",");

        return recIds.substring(0, lastIndex);
    }

    public void addOnShoppingCartStatisticsListener(OnShoppingCartStatisticsListener listener) {
        if (!mStatisticsListeners.contains(listener)) {
            mStatisticsListeners.add(listener);
        }
    }

    public void removeOnShoppingCartStatisticsListener(OnShoppingCartStatisticsListener listener) {
        mStatisticsListeners.remove(listener);
    }

    public void notifyGoodsNumberChanged(Goods goods) {
        for (OnShoppingCartGoodsItemNumberChangeListener listener : mGoodsNumberChangeListeners) {
            listener.onShoppingCartGoodsItemNumberChanged(goods);
        }
    }

    public void addOnShoppingCartGoodsItemNumberChangeListener(
            OnShoppingCartGoodsItemNumberChangeListener listener) {
        if (!mGoodsNumberChangeListeners.contains(listener)) {
            mGoodsNumberChangeListeners.add(listener);
        }
    }

    public void removeOnShoppingCartGoodsItemNumberChangeListener(
            OnShoppingCartGoodsItemNumberChangeListener listener) {
        mGoodsNumberChangeListeners.remove(listener);
    }

    /**
     * 购物车商统计接口
     */
    public interface OnShoppingCartStatisticsListener {

        /**
         * 当购物车价格与商品数量发生变化的回掉
         *
         * @param totalPriceBeforeReduce 商品总价,包含赠品的价格、运费,不包含减免的价格
         * @param totalPriceAfterReduce  商品结算的价格,包含运费、去除减免之后的价格
         * @param totalReducePrice       总的减免价格
         * @param totalSelectedCount     选择的商品与赠品的总数量
         */
        void onPriceAndSelectedCountChanged(float totalPriceBeforeReduce,
                                            float totalPriceAfterReduce,
                                            float totalReducePrice, int totalSelectedCount);

        /**
         * 购物车中的所有商品是否都被选中的回掉
         *
         * @param isSelectedAllGoods 购物车中的所有商品是否都被选中
         */
        void onAllGoodsCheckChanged(boolean isSelectedAllGoods);
    }

    /**
     * 购物车商品数量发生改变的回掉接口
     */
    public interface OnShoppingCartGoodsItemNumberChangeListener {

        /**
         * 购物车商品数量发生改变
         *
         * @param goods 数量发生改变的商品
         */
        void onShoppingCartGoodsItemNumberChanged(Goods goods);
    }

    private static class Singleton {
        private static final ShoppingCartManager instance = new ShoppingCartManager();
    }
}
